﻿Imports SNCS
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Tcp
Imports SNCS.RemoteableObject
Imports System.Data.SqlServerCe

<System.Runtime.InteropServices.ComVisible(False)>
Public Class Server
  'Implementiert das IObserver Interface, um die aktuelle Instanz des Servers, an die aktuelle Instanz des Caches anzuhängen und um die Methode Notify bereit zu stellen
  Implements RemoteableObject.IObserver

  Private Class UserContainer
    Public Property lastAccess As DateTime
    Public Property token As String
  End Class

  ''' <summary>
  ''' Definiert den Port, über den die TCP-Verbindung stattfindet.
  ''' </summary>
  ''' <remarks></remarks>
  'Const PORT = 12345


  ''' <summary>
  ''' Definiert den Namen des DienstObjekts
  ''' </summary>
  ''' <remarks></remarks>
  'Const ServiceName As String = "SNCS"

  ''' <summary>
  ''' Dieser Delegat schreibt Text in die TextBox, im Kontext des UI-Threads.
  ''' </summary>
  ''' <param name="text"></param>
  ''' <remarks></remarks>
  Delegate Sub SetTextFromUIThread(ByVal text As String)

  ''' <summary>
  ''' Das Objekt, welches über Remoting verfügbar gemacht wird.
  ''' </summary>
  ''' <remarks></remarks>
  Private _remotableObject As MyRemotableObject

  Private _authenticatedUsers As New Dictionary(Of String, DateTime)

  'Private WithEvents t1 As New Timers.Timer(10000)

  'Private Sub t1_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles t1.Elapsed
  '  Dim found As Boolean = False
  '  For Each p As Process In Process.GetProcesses
  '    If p.ProcessName.ToLower = My.Settings.SpielName.ToLower Then
  '      found = True
  '      Exit For
  '    End If
  '  Next
  '  If Not found Then End
  'End Sub
  Private WithEvents T1 As New System.Timers.Timer(1000 * 30)
  Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    '_remotableObject = New MyRemotableObject()
    't1.Enabled = True
    't1.AutoReset = True
    't1.Start()
    'Hier wird ein neuer TcpChannel mit dem gewünschten Port erstellt.
    Dim channel As TcpChannel = New TcpChannel(My.Settings.Port)

    'Vor der ersten Verwendung muss der Channel registriert werden
    ChannelServices.RegisterChannel(channel, True)

    'Damit die Übertragung funktioniert, muss der Typ, welcher beim Remoting verwendet werden soll, als WellKnownServiceType registriert werden.
    'Man kann diesen auf zwei Arten registrieren. Als Singleton oder SingleCall.

    'SingleCall: Für jeden Aufruf durch einen Client wird eine neue Instanz erstellt. Es werden keine Statusinformationen gespeichert und die Instanz des Objekts
    '            wird nach dem Aufruf zerstört und vom GC abgeholt.
    RemotingConfiguration.RegisterWellKnownServiceType(GetType(MyRemotableObject), My.Settings.ServiceName, WellKnownObjectMode.Singleton)

    'Singleton: Ein Instanz, wird für alle Aufrufe durch Clients verwendet. Es können Statusinformationen gespeichert werden.
    '           Diese Methode kann verwendet werden, um Daten zwischen zwei Clients austauschen zu können. Die Instanz des Objekts wird nach dem Aufruf nicht zerstört,
    '           sondern bleibt noch für eine gewisse Zeit erhalten (Lease-Time).
    'RemotingConfiguration.RegisterWellKnownServiceType(GetType(MyRemotableObject), ServiceName, WellKnownObjectMode.Singleton)

    'Fügt sich selbst dem Cache als IObserver-Objekt hinzu.
    RemoteableObject.Cache.Attach(Me)
    Me.Hide()
    Me.Visible = False
    T1.AutoReset = True
    T1.Start()
  End Sub



  Private _result As Boolean
  Dim tas As New MyLocalDataTableAdapters.QueriesTableAdapter
  Public Function GetValue(Name As String) As String Implements RemoteableObject.IObserver.GetValue
    Dim retv As String = String.Empty
    SyncLock tas
      Dim retval As Object = tas.GetValue(Name)
      Try
        If retval.GetType = GetType(DBNull) Then
          retv = String.Empty
        Else
          retv = retval.ToString
        End If
      Catch ex As Exception
        retv = String.Empty
      End Try
    End SyncLock
    Return retv
  End Function

  Public Function SetValue(ByVal Token As String, Name As String, Value As String) As Auxiliary.EResult Implements RemoteableObject.IObserver.SetValue
    SyncLock (_authenticatedUsers)
      If (Token IsNot Nothing) AndAlso _authenticatedUsers.ContainsKey(Token) Then
        _authenticatedUsers(Token) = DateTime.Now
        SyncLock tas
          _result = False
          If tas.UpdateValue(Value, Name) = 0 Then
            If tas.InsertValue(Name, Value) = 0 Then
              _result = False
            Else
              _result = True
            End If
          Else
            _result = True
          End If
        End SyncLock
        If _result Then
          Return Auxiliary.EResult.SUCCESS
        Else
          Return Auxiliary.EResult.FAILED
        End If
      Else
        Return Auxiliary.EResult.NOAUTH
      End If
    End SyncLock
  End Function

  Public Property Result As Boolean Implements RemoteableObject.IObserver.Result
    Get
      Return _result
    End Get
    Set(value As Boolean)
      _result = value
    End Set
  End Property

  Public Function DelValue(ByVal Token As String, Name As String) As Auxiliary.EResult Implements RemoteableObject.IObserver.DelValue
    SyncLock (_authenticatedUsers)
      If (Token IsNot Nothing) AndAlso _authenticatedUsers.ContainsKey(Token) Then
        _authenticatedUsers(Token) = DateTime.Now
        SyncLock tas
          If tas.DeleteValue(Name) = 0 Then _result = False Else _result = True
        End SyncLock
        If _result Then
          Return Auxiliary.EResult.SUCCESS
        Else
          Return Auxiliary.EResult.FAILED
        End If
      Else
        Return Auxiliary.EResult.NOAUTH
      End If
    End SyncLock
  End Function

  Public Function GetDB(ByVal Identifier As String, Optional ByVal createIfNotExist As Boolean = True) As String Implements RemoteableObject.IObserver.GetDB
    Dim retval As String = String.Empty
    SyncLock tas
      Try
        If tas.GetID(Identifier).HasValue Then
          retval = tas.GetID(Identifier).Value.ToString()
        ElseIf createIfNotExist Then
          tas.CreateDB(Identifier, Guid.NewGuid)
          retval = tas.GetID(Identifier).Value.ToString()
        Else
          retval = String.Empty
        End If
      Catch ex As Exception
        retval = String.Empty
      End Try
    End SyncLock
    Return retval
  End Function

  Public Function DelPrivateValue(ByVal Token As String, Identifier As Guid, Name As String) As Auxiliary.EResult Implements RemoteableObject.IObserver.DelPrivateValue
    SyncLock (_authenticatedUsers)
      If (Token IsNot Nothing) AndAlso _authenticatedUsers.ContainsKey(Token) Then
        _authenticatedUsers(Token) = DateTime.Now
        SyncLock tas
          Try
            If tas.PrivateDeleteValue(Name, Identifier) = 0 Then _result = False Else _result = True
          Catch ex As Exception
            _result = False
          End Try
        End SyncLock
        If _result Then
          Return Auxiliary.EResult.SUCCESS
        Else
          Return Auxiliary.EResult.FAILED
        End If
      Else
        Return Auxiliary.EResult.NOAUTH
      End If
    End SyncLock
  End Function

  Public Function GetPrivateValue(Identifier As Guid, Name As String) As String Implements RemoteableObject.IObserver.GetPrivateValue
    Dim retv As String = String.Empty
    SyncLock tas
      Try
        Dim retval As Object = tas.PrivateGetValue(Name, Identifier)
        If retval.GetType = GetType(DBNull) Then
          retv = String.Empty
        Else
          retv = retval.ToString
        End If
      Catch ex As Exception
        retv = String.Empty
      End Try
    End SyncLock
    Return retv
  End Function

  Public Function SetPrivateValue(ByVal Token As String, Identifier As Guid, Name As String, Value As String) As Auxiliary.EResult Implements RemoteableObject.IObserver.SetPrivateValue
    SyncLock (_authenticatedUsers)
      If (Token IsNot Nothing) AndAlso _authenticatedUsers.ContainsKey(Token) Then
        _authenticatedUsers(Token) = DateTime.Now
        _result = False
        SyncLock tas
          Try
            If tas.PrivateUpdateValue(Value, Name, Identifier) = 0 Then
              If tas.PrivateInsertValue(Name, Value, Identifier) = 0 Then
                _result = False
              Else
                _result = True
              End If
            Else
              _result = True
            End If
          Catch ex As Exception
            _result = False
          End Try
        End SyncLock
        If _result Then
          Return Auxiliary.EResult.SUCCESS
        Else
          Return Auxiliary.EResult.FAILED
        End If
      Else
        Return Auxiliary.EResult.NOAUTH
      End If
    End SyncLock
  End Function

  Public Function DeleteDB(ByVal Token As String, Name As String) As Auxiliary.EResult Implements RemoteableObject.IObserver.DeleteDB
    SyncLock (_authenticatedUsers)
      If (Token IsNot Nothing) AndAlso _authenticatedUsers.ContainsKey(Token) Then
        _authenticatedUsers(Token) = DateTime.Now
        Dim retval As Boolean = False
        SyncLock tas
          If tas.GetID(Name).HasValue Then
            tas.DeleteDBValues(tas.GetID(Name).Value)
            If tas.DeleteDB(tas.GetID(Name).Value) > 0 Then
              retval = True
            Else
              retval = False
            End If
          Else
            retval = False
          End If
        End SyncLock
        If retval Then
          Return Auxiliary.EResult.SUCCESS
        Else
          Return Auxiliary.EResult.FAILED
        End If
      Else
        Return Auxiliary.EResult.NOAUTH
      End If
    End SyncLock
  End Function



  Private Sub CloseToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CloseToolStripMenuItem.Click
    Me.Close()
  End Sub

  Public Function ListDBs(Optional Identifier As String = "") As List(Of String) Implements RemoteableObject.IObserver.ListDBs
    Dim retval As New List(Of String)
    SyncLock tas
      Using tab As New MyLocalDataTableAdapters.IndexTableAdapter()
        tab.ClearBeforeFill = True
        Using dt As New SNCS.MyLocalData.IndexDataTable
          tab.Fill(dt, Identifier)
          For Each dr As DataRow In dt
            retval.Add(dr(0).ToString())
          Next
          'retval '= tas.ListDBs(Identifier)
        End Using
      End Using
    End SyncLock
    Return retval
  End Function

  Public Function ListPrivateValues(Identifier As Guid, Optional Name As String = "") As Dictionary(Of String, String) Implements RemoteableObject.IObserver.ListPrivateValues
    Dim retval As New Dictionary(Of String, String)
    SyncLock tas
      Using tab As New MyLocalDataTableAdapters.PrivateSettingsTableAdapter()
        tab.ClearBeforeFill = True
        Using dt As New SNCS.MyLocalData.PrivateSettingsDataTable
          tab.Fill(dt, Identifier, Name)
          For Each dr As DataRow In dt
            retval.Add(dr(0).ToString(), dr(1).ToString())
          Next
          'retval '= tas.ListDBs(Identifier)
        End Using
      End Using
    End SyncLock
    Return retval
  End Function

  Public Function ListValues(Optional Name As String = "") As Dictionary(Of String, String) Implements RemoteableObject.IObserver.ListValues
    Dim retval As New Dictionary(Of String, String)
    SyncLock tas
      Using tab As New MyLocalDataTableAdapters.SettingsTableAdapter()
        tab.ClearBeforeFill = True
        Using dt As New SNCS.MyLocalData.SettingsDataTable
          tab.Fill(dt, Name)
          For Each dr As DataRow In dt
            retval.Add(dr(0).ToString(), dr(1).ToString())
          Next
          'retval '= tas.ListDBs(Identifier)
        End Using
      End Using
    End SyncLock
    Return retval
  End Function

  Private Sub T1_Elapsed(sender As Object, e As System.Timers.ElapsedEventArgs) Handles T1.Elapsed
    SyncLock (_authenticatedUsers)
      Dim toDelete As New List(Of String)
      For Each kv As KeyValuePair(Of String, DateTime) In _authenticatedUsers
        If Math.Abs((kv.Value - DateTime.Now).TotalSeconds) > My.Settings.AuthenticationTimeout Then
          toDelete.Add(kv.Key)
        End If
      Next
      For Each s In toDelete
        _authenticatedUsers.Remove(s)
      Next
    End SyncLock
    GC.Collect()
  End Sub

  Public Function Authenticate(User As String, Pass As String) As String Implements IObserver.Authenticate
    If My.Settings.User.ToLower = User.ToLower AndAlso My.Settings.Pass = Pass Then
      Dim token As String = Guid.NewGuid.ToString
      SyncLock (_authenticatedUsers)
        _authenticatedUsers.Add(token, DateTime.Now)
      End SyncLock
      Return token
    End If
    Return String.Empty
  End Function

  Public Function Revoke(Token As String) As Boolean Implements IObserver.Revoke
    SyncLock (_authenticatedUsers)
      If _authenticatedUsers.ContainsKey(Token) Then
        _authenticatedUsers.Remove(Token)
      End If
    End SyncLock
    Return True
  End Function
End Class
